using System;
using JetBrains.Annotations;

namespace Kaleida.ServiceMonitor.Model.Runtime
{
    public class MonitorState
    {
        [CanBeNull] private ScriptCompilation scriptCompilation;
        private bool isMonitoring;
        private int operationErrorCount;
        [CanBeNull]private OperationError firstOperationError;
        [CanBeNull]
        private OperationError latestOperationError;
        private readonly IStatePresentation statePresentation;

        public MonitorState()
        {
            statePresentation = new DefaultStatePresentation(this);
        }

        internal event EventHandler MonitorStarted;
        internal event EventHandler MonitorStopped;

        public IStatePresentation DefaultPresentation
        {
            get { return statePresentation; }
        }

        public int OperationErrorCount
        {
            get { return operationErrorCount; }
        }

        public bool IsMonitoring
        {
            get { return isMonitoring; }
        }

        public bool CanBeginMonitoring
        {
            get { return !isMonitoring && HasSuccessfullyCompiledScript; }
        }

        public bool HasScriptError
        {
            get { return scriptCompilation != null && !scriptCompilation.Succeeded; }
        }

        public bool HasSuccessfullyCompiledScript
        {
            get { return scriptCompilation != null && scriptCompilation.Succeeded; }
        }

        public bool HasOperationFailures
        {
            get { return operationErrorCount != 0; }
        }

        [CanBeNull]
        public ScriptCompilation ScriptCompilation
        {
            get { return scriptCompilation; }
        }

        public OperationError FirstOperationError
        {
            get { return firstOperationError; }
        }

        public OperationError LatestOperationError
        {
            get { return latestOperationError; }
        }

        internal void FlagError(OperationError error)
        {
            if (firstOperationError == null)
                firstOperationError = error;

            latestOperationError = error;

            operationErrorCount++;
        }

        public void ClearErrors()
        {
            operationErrorCount = 0;
            firstOperationError = null;
            latestOperationError = null;
        }

        public void ScriptCompiled(ScriptCompilation compilation)
        {
            isMonitoring = isMonitoring && compilation.Succeeded;
            scriptCompilation = compilation;
        }

        public void StartMonitoring()
        {
            if(!CanBeginMonitoring)
                throw new InvalidOperationException("Monitor is not in a suitable state to start");

            isMonitoring = true;

            if (MonitorStarted != null)
                MonitorStarted(this, EventArgs.Empty);
        }

        public void StopMonitoring()
        {
            if (!IsMonitoring)
                throw new InvalidOperationException("Monitor is already started");

            isMonitoring = false;

            if (MonitorStopped != null)
                MonitorStopped(this, EventArgs.Empty);
        }
    }
}